package expression;

import NextClass.NativeClass;
import NextClass.NextClassAPI;
import vm.baseNativeUseFunction.NativeUseFunction;
import vm.runtime.NextVMRuntime;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;

public class StringExpression implements Serializable {
    public static String getExpression
            (
            String expression,
            NextVMRuntime nextVMRuntime)
    throws Exception
    {
        String[] tokens = expression.split(
                ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)(?=([^(]*\\([^)]*\\))*[^)]*$)"
        );
        StringBuffer stringBuffer = new StringBuffer();
        for (String string : tokens) {
            string = string.trim();
            Object Values = getValueFromNextVM(string , nextVMRuntime);
            if (string.isEmpty()) {
                continue;
            }
            else if (string.startsWith("\"") && string.endsWith("\"")) {
                try {
                    String ss = string.substring(1,string.length()-1);
                    stringBuffer.append(ss);
                    continue;
                }
                catch (Exception exception) {
                    throw new Exception("string error.");
                }
            }
            if (NativeUseFunction.IsNativeUseFunctionCode(string)) {
                stringBuffer.append(NativeUseFunction.run_code(string,nextVMRuntime));
                continue;
            }
            NativeClass nativeClass = NextClassAPI.IsNativeClassInvokeCode(string , nextVMRuntime);
            if (nativeClass != null) {
                String Name = string.substring(0 , string.indexOf("(")).trim();
                String Invoke = Name.substring(Name.indexOf(".")+1).trim();
                String Content = string.substring(string.indexOf("(")+1,string.lastIndexOf(")")).trim();
                String regex = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)(?=([^\\(]*\\([^\\)]*\\))*[^\\)]*$)";
                String[] split = Content.split(regex);
                Object[] objects = BaseExpression.Deal(split,nextVMRuntime);

                stringBuffer.append( nativeClass.run(Invoke,nextVMRuntime,objects));
                continue;
            }
            NextVMRuntime UseFunction = MathExpression.CodeFunctionFromRuntime(string, nextVMRuntime);
            if (UseFunction != null) {
                UseFunction.run();
                stringBuffer.append(UseFunction.ReturnContent);
                continue;
            }
            else if (Values != null) {
                stringBuffer.append(Values);
                continue;
            } else if (isList(string , nextVMRuntime , stringBuffer)) {
                continue;
            }
            else {
                throw new Exception("Unknown Expression: "+string+" in "+expression);
            }
        }
        return stringBuffer.toString();
    }
    public static boolean IsNumber(String string) {
        try {
            double b = Double.parseDouble(string);
            return true;
        }catch (Exception e) {
            return false;
        }
    }
    public static Object getValueFromNextVM(String valueName, NextVMRuntime nextVMRuntime) {
        Object obj_1 = nextVMRuntime.values.get(valueName);
        if (obj_1 != null) {
            return obj_1;
        }
        else if (nextVMRuntime.LastRuntime != null) {
            return getValueFromNextVM(valueName , nextVMRuntime.LastRuntime);
        } else {
            return null;
        }
    }
    private static boolean isList(String code , NextVMRuntime nextVMRuntime,StringBuffer stringBuffer) throws Exception {
        try {
            String value = code.substring(0 , code.indexOf("[")).trim();
            String input = code.substring(code.indexOf("[")+1 , code.lastIndexOf("]")).trim();
            Object object = getValueFromNextVM(value , nextVMRuntime);
            if (object != null) {
                int index = (int) MathExpression.evaluateExpression(input , nextVMRuntime);
                ArrayList<Object> arrayList = (ArrayList<Object>) object;
                stringBuffer.append(arrayList.get(index));
            } else {
                throw new Exception("Unknown Value: "+value);
            }
            return true;
        }catch (Exception exception) {
            return false;
        }
    }
    public static Object GetListValue(String code , NextVMRuntime nextVMRuntime) throws Exception {
        try {
            String value = code.substring(0 , code.indexOf("[")).trim();
            String input = code.substring(code.indexOf("[")+1 , code.lastIndexOf("]")).trim();
            Object object = getValueFromNextVM(value , nextVMRuntime);
            if (object != null) {
                int index = (int) MathExpression.evaluateExpression(input , nextVMRuntime);
                ArrayList<Object> arrayList = (ArrayList<Object>) object;
                return arrayList.get(index);
            } else {
                throw new Exception("Unknown Value: "+value);
            }
        }catch (Exception exception) {
            return null;
        }
    }

}
